/**
 * 
 * @Project HRL Simulation
 * @Date 20.06.2011
 * @Author Aebi Pascal, Kocher Marc, Sriranjan George
 * @School BFH-TI Biel, Projekt 1
 *
 */

package elements;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import exceptions.ResourceException;

import utils.AgendaEntry;
import utils.Locator;
import utils.Position;
import utils.Resource;
import utils.SkipList;


/**
 * The class Rack.
 * It is responsible for storing loads at specified positions.
 */
public class Rack {
	
	private final int SL_END = Integer.MAX_VALUE;
	private final int SL_START = new Integer(-1); //because -1 = infinite
	private SkipList resources = new SkipList(this.SL_START, this.SL_END, 0);
	private Position position;
	private int length;
	private int height;
	
	
	/**
	 * Instantiates a new rack.
	 * 
	 * @param position the initial position of the rack
	 * @param length the length of the rack
	 * @param height the height of the rack
	 */
	public Rack(Position position, int length, int height){
		this.position = position;
		this.length = length;
		this.height = height;
		this.constructRack();
	}
	
	
	/**
	 * Construct all rack resources
	 */
	private void constructRack(){
		int free = 0;
		for(int i=0; i<height; i++){
			for(int j=0; j<length; j++){
				Position newPos = new Position(position.getX(), j+position.getY(), i);
				Resource newRes = new Resource(newPos);
				this.resources.insertItem(free, newRes);
			}
		}
	}
	
	/**
	 * get a list of all free resources in the rack for a given time.
	 * @param time to check if the rack has free resources.
	 * @return list of free resources
	 */
	public List<Resource> getFreeResources(int time){
		List<Resource> freeRes = new ArrayList<Resource>();
		Iterator<?> it = this.resources.locators();
		Locator loc = null;
		Resource res = null;
		int t;
		
		while(it.hasNext()){
			loc = (Locator)it.next();
			res = (Resource)loc.element();
			t = res.getAgenda().getLastEntry().getEndTime();
			if(t <= time && t >= 0){
				freeRes.add(res);
			}
		}
		return freeRes;
	}
	
	/**
	 * get a list of all resources in the rack
	 * @return list of resources
	 */
	public List<Resource> getAllResources(){
		List<Resource> resources = new ArrayList<Resource>();
		Iterator<?> it = this.resources.locators();
		Locator loc = null;
		Resource res = null;
		
		while(it.hasNext()){
			loc = (Locator)it.next();
			res = (Resource)loc.element();
			resources.add(res);
		}
		return resources;
	}
	
	
	/**
	 * the last entry with end time infinite will be replaced by a new entry with the given end time
	 * @throws ResourceException  position not found
	 */
	public void releaseResource(Resource res, int time) throws ResourceException {
		Iterator<?> it = this.resources.locators();
		Locator loc = null;
		int infinite = this.SL_END-1;
		AgendaEntry lastAE  = res.getAgenda().getLastEntry();
		AgendaEntry newAE = new AgendaEntry(lastAE.getStartTime(), res.getPosition(), time, res.getPosition(), res.getAgenda().getLastEntry().getLoad());
		boolean found = false;
		while(it.hasNext()){
			loc = (Locator)it.next();
			Resource resNext = (Resource)loc.element();
			if(res.equals(resNext)){
				if(lastAE.getEndTime() >= time && lastAE.getEndTime() == infinite){
					this.resources.insertItem(time, res);
					this.resources.removeItem(loc);
					res.getAgenda().removeEntry(lastAE);
					res.getAgenda().addEntry(newAE);
					found = true;
					break;
				}
			}
		}
		
		if(!found){
			throw new ResourceException("Couldn't release the resource. Resource at position"+res.getPosition());
		}
	}

	
	/**
	 * Checks if the skip list contains a given resource
	 * 
	 * @param resource - the resource which is to be looked for
	 * @return boolean - true if exists
	 */
	public boolean contains(Resource resource){
		Iterator<?> it = this.resources.locators();
		Locator loc = null;
		Resource res = null;
		
		while(it.hasNext()){
			loc = (Locator)it.next();
			res = (Resource)loc.element();
			if(resource.equals(res)){
				return true;
			}
		}
		return false;
	}
	
	/**
	 * search the rack resource with this load
	 * @param load to search
	 * @return rack resource
	 */
	public Resource getResourceOfLoad(Load load){
		Iterator<?> it = this.resources.locators();
		Locator loc = null;
		Resource res = null;
		
		while(it.hasNext()){
			loc = (Locator)it.next();
			res = (Resource)loc.element();
			Load loadFromRack = res.getAgenda().getLastEntry().getLoad();
			if(loadFromRack != null && loadFromRack.equals(load)){
				return res;
			}
		}
		return null;
	}
	
	/**
	 * get rack position
	 * @return position
	 */
	public Position getRackPosition(){
		return this.position;
	}

	/**
	 * print all resources
	 */
	public void printAllResources(){
		this.resources.printAll();
	}
	
	@Override
	public String toString() {
		return "rack position: " + this.position + " size: " + this.length + "x" + this.height;
	}
	
}
